﻿/*
* Copyright (c) 2011, Johnson County Community College (JCCC)
* All rights reserved.
* BSD License: http://www.opensource.org/licenses/bsd-license.php
* 
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
*    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 
*      in the documentation and/or other materials provided with the distribution.
*    * Neither the name of JCCC nor the names of its contributors may be used to endorse or promote products derived 
*      from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

using System;
using System.Collections.Generic;

public class Dijkstra2DMap
{
    /// <summary>
    /// Width of the map, needed to go from 1D to 2D
    /// </summary>
    public int width;
    public int[] djMap;
    public List<int> goalIndicies;
    public List<int> blockedIndices;
    public int defaultValue;
    bool dirty = false;
    public List<int> closedNodes;
    public Queue<int> openNodes;

    //public Utility.Logging.Logger log;

    //public Dijkstra2DMap(Game game)
    public Dijkstra2DMap()
    {
        goalIndicies = new List<int>();
        blockedIndices = new List<int>();
        openNodes = new Queue<int>();
        closedNodes = new List<int>();
        //log = (Utility.Logging.Logger)game.Services.GetService(typeof(Utility.Logging.Logger));
        width = -1;
    }
    #region SetGoal
    /// <summary>
    /// SetGoal sets a goal point for the Dijkstra algorithm
    /// </summary>
    /// <param name="x">X coordinate of the goal</param>
    /// <param name="y">Y coordinate of the goal</param>
    public void SetGoal(int x, int y)
    {
        this.SetGoal(y * this.width + x);
    }

    /// <summary>
    /// SetGoal sets a goal point for the Dijkstra algorithm
    /// </summary>
    /// <param name="index">1D index of the goal</param>
    public void SetGoal(int index)
    {
        if (goalIndicies.Contains(index))
        {
            //if (log != null) log.WriteError("Dij: Attempted to add in an existing goal index");
        }
        else
        {
            goalIndicies.Add(index);
            dirty = true;
        }
    }
    #endregion

    #region SetBlocked
    public void SetBlocked(int x, int y)
    {
        this.SetBlocked(y * this.width + x);
    }

    public void SetBlocked(int index)
    {
        if (blockedIndices.Contains(index))
        {
            //if (log != null) log.WriteError("Dij: tried to add duplicate blocked index");
        }
        else
        {
            blockedIndices.Add(index);
        }

    }
    #endregion

    public void createMap(int width, int height, int defaultValue)
    {
        djMap = new int[width * height];
        this.width = width;
        this.defaultValue = defaultValue;
        ResetMap();
    }

    public void ResetMap()
    {
        for (int i = 0; i < djMap.Length; i++) djMap[i] = defaultValue;

        //setGoals
        for (int i = 0; i < goalIndicies.Count; i++) djMap[goalIndicies[i]] = 0;

        //set blocked
        for (int i = 0; i < blockedIndices.Count; i++) djMap[blockedIndices[i]] = int.MaxValue;
    }

    public void run()
    {
        foreach (int curGoal in goalIndicies) runDij(curGoal);
    }

    public void runDij(int goal)
    {
        openNodes.Clear();
        closedNodes.Clear();
        openNodes.Enqueue(goal);
            
        int target;
        int curNode;

        while (openNodes.Count != 0)
        {
                //lookup
            curNode = openNodes.Dequeue();
            target = curNode - width;
            if (target >= 0 && djMap[target] != int.MaxValue)
            {
                UpdateNode(target, curNode);
            }
            //look down
            target = curNode + width;
            if (target < djMap.Length && djMap[target] != int.MaxValue)
            {
                UpdateNode(target, curNode);
            }
            //look left
            target = curNode - 1;
            if(curNode % width != 0 && target >=0 && djMap[target] != int.MaxValue)
            {
                UpdateNode(target, curNode);
            }
            //look right
            target = curNode + 1;
            if (curNode % width != (width - 1) && target < djMap.Length && djMap[target] != int.MaxValue)
            {
                UpdateNode(target, curNode);
            }

        }//end while
    }

    private void UpdateNode(int target, int curNode)
    {
        if (djMap[target] > djMap[curNode] + 1)
        {
            djMap[target] = djMap[curNode] + 1;
            openNodes.Enqueue(target);
        }
    }

    public void LogDijMap()
    {
#if XBOX
        return;
#else
        System.Text.StringBuilder result = new System.Text.StringBuilder();
        result.AppendLine("********************START LOG OF DIJKSTRA MAP****************");
        result.Append(string.Format("{0:0000000000} ", djMap[0]));            
        for (int i = 1; i < djMap.Length; i++)
        {
            if (i % width == 0) result.AppendLine();
            result.Append(string.Format("{0:0000000000} ", djMap[i]));
        }
        //if (log != null) log.WriteDebug(result.ToString());
#endif

    }

}

